home *** CD-ROM | disk | FTP | other *** search
Text File | 1992-03-14 | 81.4 KB | 2,134 lines |
-
-
- RexxRMF.Library
-
- (version 1.8 Mar. 1992)
-
-
-
-
- The RexxRMF.library is a library which gives ARexx programs the ability
-
- to maintain 'indexes' of small files for the purpose of providing fast
-
- search/sorting and retrieval of data records.
-
- The RexxRMF.library consists of several 'low' level functions that are
-
- used to maintain a balanced binary tree (AVL-tree) to index your
-
- data files. Built on top of the AVL-tree routines are 'high' level
-
- functions to provide simple Record Management Facilities.
-
-
-
- The record management functions allow for:
-
- Variable length keys
-
- Variable length records
-
- Duplicate keys
-
- Mulitple indexes (ie. you can use alternate keys)
-
- Passing of record data directly to/from ARexx variables.
-
-
-
-
- eg.
- /* an example ARexx pgm might be */
-
- x = addlib("RexxRMF.library",0,-30,0) /* make lib available */
- index = open_rmf("phonelist") /* open index file */
- myrecord = "lastname firstname phonenumber" /* define record */
- x = writech(stdout,"Enter Name:") /* get search key */
- parse pull name
- x = read_rmf_record(index,0,myrecord,name,'K') /* read record */
- if x = 1 then
- say firstname lastname phonenumber /* print record */
- else
- say name "Not Found
- x = close_rmf(index,1)
- exit
-
- In order to use the RexxRMF.library simply place it in your LIBS:
- directory.
-
-
- RexxRMF.Library
-
-
-
- RexxRMF library builds and maintains an AVL-tree in memory to index your
- data files. Since the entire tree is always in memory it should be
- EMPHASIZED that RexxRMF was INTENDED for SMALL files. How small depends
- on how much memory you have. The amount of memory used will depend greatly
- on the length of the keys and how many alternate indices you build.
-
- RexxRMF allows you to specify up to five alternate indices. What this
- means is that you can have multiple keys for the same file. This allows
- you not only to read a file by lastname for example, but you could also
- use the month in which a person was born as an alternate key index, so
- that you could send the person a birthday card in time for his/her
- birthday.
-
- In addition to the primary and alternate indices RexxRMF internally
- maintains a "delete" index in order to locate and keep track of deleted
- records. In all, as many as seven indices could be present in memory
- at any one time for a given file. Each node (record) will require about
- 76 + keylength bytes per record. Thus 2000 records could easily consume
- 170K bytes.
- Your memory configuration will determine how large 'small' can be.
-
- Data records on the other hand are loaded into memory when read/written
- and immediately get discarded afterwards. Data records can have as
- many fields as you wish as long as the total length of the record is
- less than 65K bytes and the total number of fields is less than 65K.
- With the exception of header information placed at the beginning of
- each record all data records are written as null terminated ASCII text.
- Thus the datafile can be viewed with a good editor, or a "filezap" type
- program, the data contents should be readily apparent.
-
- Since all indices are maintained in memory, all updates to them occur
- in memory. The index file is not written to disk until the you close
- the index with the CLOSE_RMF() function, the data file is updated
- immediately. Their exists the possiblity that if your Amiga crashes
- anytime before the index is closed, then the index and data file will
- be out of sync. It is possible to rebuild the primary index from the
- datafile itself. Included with the RexxRMF library are two utility
- programs that can be used to rebuild the primary index.
-
- The library functions are fairly simple to use. The functions provide
- for the common (basic) file operations of adding, changing and
- deleting records. The RexxRMF library passes data from the datafile
- directly to variables in your ARexx program. You tell RexxRMF which
- program variables are to receive data by passing to the RexxRMF library
- functions the names of the variables. Data record variables are read
- and written in the order you specify. The variable names must conform
- to ARexx naming rules and stem/compound variables are not supported.
-
- The function descriptions and discussion below describe the details of
- using each function.
-
-
- RexxRMF.Library
-
-
-
-
-
- Record Management Functions
-
- Eight functions are provided for managing data file records.
-
- 1). OPEN_RMF()
- 2). WRITE_RMF_RECORD()
- 3). READ_RMF_RECORD()
- 4). NEXT_RMF_RECORD()
- 5). UPDATE_RMF_RECORD()
- 6). UPDKEY_RMF_RECORD()
- 7). DELETE_RMF_RECORD()
- 8). CLOSE_RMF()
-
-
- These functions access your ARexx program variables directly, in order
- to read/write the data file. You only need to specify the record
- layout and the names of the variables within the record.
-
- The functions require two files (which are automatically created) to be
- present:
-
- 1). the data file
- which contains the actual data records
-
- 2). the index file
- which is the file that contains the tree information.
-
- If you create a file using these routines then it is probably best
- that you use only these routines to manage them, since it is real
- easy screw to up the indices.
-
-
- Function Usage
-
- To use the functions simply call them by name as you would with
- any other ARexx or library function.
-
- The functions described below require that the names of the fields
- to read/write be placed in an ARexx string variable or literal,
- which I will call the 'record layout string'. A simple assignment
- statement accomplishes the creation of the record layout string.
-
- eg. RECORD LAYOUT STRING
-
- myrecordlayout = "firstname lastname phonenumber dateofbirth"
-
- When the functions are called, the data will be read/written
- in the order specified in the string. The variable names used
- in the string must conform to ARexx variable name rules.
- ( Stem and Compound variables are not supported)
-
- Within the record layout string you may insert 'special' variables
- which will cause additional information to be returned to your
- ARexx program. (see Special Symbol Variables below)
-
- RexxRMF.Library
-
-
-
-
-
- Record Management Function Descriptions
-
-
- OPEN_RMF
-
- Opens RMF data and index files for use.
-
- ix = OPEN_RMF([filename] [,dup0] [,nodata])
-
- OPEN_RMF accepts 3 arguments all optional.
-
- Inputs:
-
- 1). filename - the name of the data file to be indexed.
- If the index file does not exists a new
- one will be created. The index file will
- have a suffix of '.rmfindex'.
-
- 2). dup0 - numeric, specifies whether the primary
- index (0) can have duplicate keys.
- This argument is optional. Note this does
- not apply to any of the alternate indices,
- alternate indices always allow duplicates.
-
- Code this as either 0 or 1.
-
- 0 means duplicate keys *ARE* allowed
- 1 means duplicate keys are not allowed
- The default is 0, duplicates allowed.
-
- 2). nodata - numeric, specifies whether a data file
- should be created/maintained.
-
- Code this as either 0 or 1.
-
- 0 means create a data file
- 1 means do NOT create a data file
- The default is 0, create a data file.
-
-
- RexxRMF.Library
-
-
- OPEN_RMF
-
-
- eg.
- ix = open_rmf(myfile)
- opens/creates both a data and index file, with duplicates
- ALLOWED.
-
- ix = open_rmf(myfile,1)
- opens/creates both a data and index file, with duplicates
- NOT ALLOWED.
-
- The above open calls are the ways you would normally open
- the files for use.
-
-
- The following open calls are also legal.
-
- ix = open_rmf() or open_rmf("")
-
- ix = open_rmf("",1) - specifies nodups
-
- neither an index nor data file are created, 'ix' will
- be valid and can only be used with the 'low' level
- functions. The index cannot be saved since no filename
- is specified. This form uses the AVL-tree for its sort/
- search functions, nothing can be saved.
-
- ix = open_rmf(myfile,1,1)
-
- open/create an index file, duplicates NOT allowed, no
- data file is opened/created. You cannot use any of the
- ..._RMF_RECORD functions. The index can be saved.
-
- ix = open_rmf(myfile,0,1)
-
- open/create an index file, duplicates allowed, no
- data file is opened/created. You cannot use any of the
- ..._RMF_RECORD functions. The index can be saved.
-
- The intent of the above two forms is to allow you the
- ability to use RexxRMF to index your data, but leaves
- the managing (reading/writing) of the data records
- themselves to you.
-
- ix = open_rmf(myfile,0,0) is the same as open_rmf(myfile)
-
- ix = open_rmf(myfile,1,0) is the same as open_rmf(myfile,1)
-
-
-
- The data or index files will only be created if they do not
- currently exists. Otherwise the existing files are used, this
- allows you to verify the index if it were rebuilt using the
- the utility program 'rebuildrmfindex' described below.
-
-
- OPEN_RMF will return non-null if the call succeeds.
- The returned value is an ARexx 'packed' hex string.
- This value is used by the other record management functions
- to access the tree and the data file. Basically this value
- points to global data needed by the other functions.
- DO NOT manipulate this value in anyway.
-
- RexxRMF.Library
-
-
-
-
-
- WRITE_RMF_RECORD
-
- Writes a new record to the data file.
-
- x = WRITE_RMF_RECORD(ix,record,key,[{ixnum1,altkey1} ... 5 ])
-
- WRITE_RMF_RECORD accepts up to 13 arguments, three of which are
- required arguments. The other ten arguments are optional.
- The ten optional arguments specify alternate index/key pairs to
- be associated with the record. WRITE_RMF_RECORD will always write
- the primary index (index #0)
-
-
- Inputs:
-
- 1). ix - global data pointer (from OPEN_RMF())
-
- 2). record - record layout string
-
- 3). key - is an ARexx variable or literal to be used as
- the key for the record. This is the key that
- will be used to write the primary index (#0).
-
- 4-13). num,key - specified in pairs, these arguments identify
- alternate indices and the key to be used with
- the index. Up to 5 alternate pairs can be used.
- The index numbers must be between 1 and 5,
-
- The indices can be specified in any order, at
- anytime. (ie. index #1 need not be used before
- index #3 or #4 are used)
-
- Be aware that additional indexes are implemented
- as individual binary trees, and therefore take
- as much memory (or more depending on keylength)
- as the primary index.
-
- If index 0 is specified as an alternate,
- it will simply be ignored.
-
- If the file has been created with duplicates
- not allowed the write will fail, if the key
- currently exists in the file.
-
- WRITE_RMF_RECORD returns 1 if the write succeeds, otherwise 0.
-
- RexxRMF.Library
-
-
-
- WRITE_RMF_RECORD
-
-
- eg.
-
- 1 myrecord = "firstname lastname area phonenumber"
- 2 name = "Kelly"
- lastname = "Kelly"
- firstname = "Ronnie"
- area = 999
- phonenumber = "555-1212"
- 3 x = WRITE_RMF_RECORD(ix,myrecord,name)
- or x = WRITE_RMF_RECORD(ix,myrecord,lastname)
-
- stmt. 1: defines the ARexx variable names that
- will be accessed and written to the data file.
-
- Also defines the layout of the data record, ie. the
- fields will be written in the order specified. This
- is important, the same order must be used to read the
- data with READ_RMF_RECORD().
-
- stmt. 2: gives 'name' the value 'Kelly', name will then be
- used as the key.
-
- stmt. 3: adds (writes) the record to the data file and updates
- the primary index with the key value taken from name.
- The primary index is always written.
- 'myrecord' specifies the names of the ARexx
- variables to use, the values of these variables
- are obtained by the RMF library function.
-
-
- eg.
- x = WRITE_RMF_RECORD(ix,myrecord,name,4,area)
-
- this statement adds the record to the file, and updates the
- primary index with the key value taken from name. Also
- alternate index number 4 is updated with key value taken
- from the field area. You (or the program) must now
- remember that index number 4 is indexing on area.
-
-
- eg.
- x = WRITE_RMF_RECORD(ix,myrecord,lastname,4,area,2,firstname)
-
- this statement adds the record to the file, updates the
- primary index with the key value taken from lastname.
- Two alternate indices are used index number 4 is indexing on
- area, and index number 2 in indexing on firstname.
-
- Note that in the two previous examples the indices were not used
- in order, ie. indices 2 and 4 were specified, but 1 and 3 were
- not. If you later decide to use indices 1 or 3 then you should
- use an UPDATE_RMF_RECORD specifying indices 1 or 3 (or both).
- (See UPDATE_RMF_RECORD description)
-
-
- RexxRMF.Library
-
-
-
- WRITE_RMF_RECORD
-
-
-
- eg.
- x = WRITE_RMF_RECORD(ix,myrecord,'Kelly',4,area,2,fname)
- x = WRITE_RMF_RECORD(ix,myrecord,'Kelly',4,area,2,fname,3,zip)
-
- The above sequence would cause two records to be written, the
- first would have primary index value of 'Kelly', index 4 will
- have the value of area, and index 2 would have the value
- of firstname.
- The second statement causes a second (duplicate) record to be
- written with the same index values for the primary index and
- indices 2 and 4. In addition a entry would be made in index
- 3 for the zip code.
-
- If your intent is to start using index 3 for zipcodes then
- the following sequence should be used:
-
- WRITE_RMF_RECORD(ix,myrecord,'Kelly',4,area,2,firstname)
- UPDATE_RMF_RECORD(ix,myrecord,'Kelly',4,area,2,firstname,3,zip)
-
- With the above sequence a second record would not be added,
- but an entry will be made into index 3 for the zip code.
-
- To have all existing records indexed by a new index you have
- to sequentially read through the entire file updating each
- record with the new index field.
-
- RexxRMF.Library
-
-
- READ_RMF_RECORD
-
- Read data record from file.
-
- x=READ_RMF_RECORD(ix,ixnum,record,key,{'K'|'R'|'P'|'U'|'L'},[occur])
-
- READ_RMF_RECORD accepts six arguments, five required plus one optional.
-
- Inputs:
-
- 1). ix - global data pointer (from OPEN_RMF())
-
- 2). ixnum - integer specifies which index to use
- this should be a numeric whos value is
- between 0 and 5.
- value 0 specifies the 'primary' index
- value 1 - 5 specify alternate index.
-
- 3). record - record layout string
- If the read is successful the ARexx variables
- named in this string will be loaded with data
- from the record that was read.
-
- 4). key - is an ARexx variable or literal to be used as
- the record key to read (search) for.
-
- 5). rdtype - this parameter must be either K, R, P, L, or U.
-
- If 'K' it specifies that the 'key' argument
- is actually a string KEY. READ_RMF_RECORD
- will read for the record with this string key,
- the entire key must match, including occurence.
-
- If 'P' it specifies that the 'key' argument
- is actually a string KEY. READ_RMF_RECORD
- will read for the record with this string key.
- However partial matches of the key will
- result in success. ie. the 'key' specifies a
- sub-string anchored at the beginning of the key.
-
- If 'R' it specifies that the 'key' argument
- is actually a NUMERIC record number.
- READ_RMF_RECORD will then read the record
- number specified by 'key', 'key' must have a
- numeric value. Reading by record number order
- is the same as reading in key sorted order.
-
- If 'L' it specifies that the 'key' argument
- is actually a NUMERIC record number.
- READ_RMF_RECORD will then read the record
- number specified by 'key' in reverse order,
- 'key' must have a numeric value.
- eg. if ...,'L',1) reads last record
- if ...,'L',2) reads next to last record
- if ...,'L',3) reads 2nd from last record
- etc.
- ie. 'R' reads from top to bottom (ascending)
- 'L' reads from bottom to top (descending)
- If a subsequent NEXT_RMF_RECORD() call is made
- the next to the last record is read, etc.
- (see NEXT_RMF_RECORD)
-
- If 'U' it specifies that the 'key' argument
- is actually a string KEY. READ_RMF_RECORD
- will read for the FIRST occurence of the key,
- the 'occur' argument is ignored. Primarly
- intended for reading unique keys in the file.
- (see NEXT_RMF_RECORD)
-
- 6). occur - is a numeric variable or literal which
- specifies which occurence of a key to read.
- Multiple keys with the same value are uniquely
- identified by an occurence number. (default 1)
-
- READ_RMF_RECORD returns 1 if the read succeeds, otherwise 0.
-
- RexxRMF.Library
-
-
-
- READ_RMF_RECORD
-
- eg.
-
- 1 myrecord = "firstname lastname phonenumber"
- 2 recordnum = 27
- 3 x = READ_RMF_RECORD(ix,0,myrecord,recordnum,'R')
- 4 if x = 1 then
- 5 say firstname lastname phonenumber
- 6 else say "Record Not Found"
-
- stmt. 1: defines the ARexx variable names that
- will be accessed and loaded with data.
-
- stmt. 2: gives 'recordnum' the value 27
-
- stmt. 3: reads (searches the tree) the data file for record
- number 27 (value of recordnum) and returns 1 if
- successful. If successful then the ARexx variables
- firstname, lastname, phonenumber will contain the
- contents from record 27.
-
- eg.
- x = READ_RMF_RECORD(ix,0,myrecord,27,'R')
- does the same as above, read record #27.
-
- x = READ_RMF_RECORD(ix,0,myrecord,27,'K')
- search for record whose key is '27', this is NOT the
- same as the 27th record. (entire key must match)
-
- x = READ_RMF_RECORD(ix,0,myrecord,"Kel",'P')
- will search for the FIRST record who's key begins with
- "Kel", partial key match. ( searches are case sensitive)
-
- x = READ_RMF_RECORD(ix,0,myrecord,"Kelly",'K',3)
- will search for the THIRD occurence of a record who's
- key is "Kelly". Note if less than 3 exists then the
- read will fail.
-
- x = READ_RMF_RECORD(ix,0,myrecord,"Kel",'P',4)
- will search for the FOURTH occurence of a record who's
- key begins with "Kel".
- (partial match beginning with "Kel")
-
- If the index (and data file) contains the keys
-
- Adams occurence 1
- Adams occurence 2
- Adams occurence 3
- Keller occurence 1
- Kelly occurence 1
- Kelly occurence 2
- Kelvin occurence 1 <-- 4th key beginning with "Kel"
- then
-
- x = READ_RMF_RECORD(ix,0,myrecord,"Kel",'P',4)
-
- will return the record for 'Kelvin'
-
- ---------
-
- NOTE: if a data field is null, then RexxRMF will return
- a string value of "(null)". This is so that it is
- immediately apparent that the field contains no data.
- If you want it to truly be null, then you will have
- to assign it a null value again.
-
- ie. if phonenumber = "(null)" then phonenumber = ''
-
-
- RexxRMF.Library
-
- NEXT_RMF_RECORD
-
- Read the next record from the data file.
-
- x = NEXT_RMF_RECORD(ix,ixnum,record)
-
- NEXT_RMF_RECORD should only be called immediately after
- a READ_RMF_RECORD has been made. NEXT_RMF_RECORD will
- then return in sequential order the next record that
- satisfies the most recent READ_RMF_RECORD call,
-
- NEXT_RMF_RECORD accepts three arguments, all required.
-
- Inputs:
-
- 1). ix - global data pointer (from OPEN_RMF())
-
- 2). ixnum - integer specifies which index to use
- this should be a numeric whos value is
- between 0 and 5.
- value 0 specifies the 'primary' index
- value 1 - 5 specify alternates.
-
- 3). record - record layout string
-
- NEXT_RMF_RECORD returns 1 if the read succeeds, otherwise 0.
-
- eg. If the index (and data file) contain the keys
-
- record# 1 1Adam12 occurence 1
- 2 1Adam12 occurence 2
- 3 1Adam12 occurence 3
- 4 1Adam22 occurence 1
- 5 1Adam22 occurence 2
- 6 27aint11 occurence 1
- 7 27aint11 occurence 2
- 8 27aint11 occurence 3
- 9 27aint11 occurence 4
- 10 27aint11 occurence 5
- 11 27aint7 occurence 1
- 12 27aint7 occurence 2
- 13 3MaryAdam occurence 1
-
- most recent most recent successive calls to
- READ_RMF_RECORD READ_RMF_RECORD NEXT_RMF_RECORD
- (ix,0,myrecord, ... returns return
- record # record #s
-
- ...,4,'R') 4 5,6,7,8,9,10,11,12,fail
-
- ...,"27aint11",'K') 6 7,8,9,10,fail
-
- ...,"27",'P') 6 7,8,9,10,11,12,fail
-
- ...,"27",'P',6) 11 12,fail
- (6th occurence of '27')
-
- ...,"1Adam12",'U') 1 4,6,11,13,fail
- (starting with "1Adam12"
- return all unique keys)
-
- ...,1,'L') /*reverse order*/ 13 12,11,10,9,8,7,6,5,4,3,2,1,fail
-
- ...,3,'L') 10 9,8,7,6,5,4,3,2,1,fail
-
- RexxRMF.Library
-
-
-
-
-
- UPDATE_RMF_RECORD
-
- UPDATE_RMF_RECORD is used to update a record by record number.
- The record number is the number of the record in key sorted
- order.
-
- eg. If your file contained two records with keys A and C,
- then the record with key A is record number 1,
- and the record with key C is record number 2.
- If you then add a new record to the file with key B
- then record A is record 1, record B becomes record 2
- and record C becomes record 3.
-
- The primary key will not be updated, so if you are updating
- the *PRIMARY* key of a record you should use UPDKEY_RMF_RECORD,
- and not UPDATE_RMF_RECORD. Note that alternate index keys can
- be updated with UPDATE_RMF_RECORD.
-
- x = UPDATE_RMF_RECORD(ix,record,recnum,[{ixnum1,altkey1}...])
-
- UPDATE_RMF_RECORD accepts 13 arguments, 3 required, 10 optional.
-
- Inputs:
-
- 1). ix - global data pointer (from OPEN_RMF())
-
- 2). record - is a string which contains the variable names.
- (ie. record layout string)
-
- 3). recnum - is a numeric ARexx variable or string specifing
- which record number to update.
-
- 4-13). - alternate index key pairs
- these arguments must be specified in pairs
- they specify the alternate indexes and the
- key to be used with that index.
- If not specified the alternate index retains
- its current value when the record is updated.
-
-
- UPDATE_RMF_RECORD returns 1 if the update succeeds, otherwise 0.
-
- RexxRMF.Library
-
-
-
-
-
- UPDATE_RMF_RECORD
-
-
-
- eg.
-
- 1 myrecord = "firstname lastname phonenumber"
- 2 recordnum = 27
- 3 x = READ_RMF_RECORD(ix,myrecord,recordnum,'R')
- 4 phonenumber = " (219) 555-5555 "
- 5 x = UPDATE_RMF_RECORD(ix,myrecord,recordnum)
-
- stmt. 1: defines the ARexx variable names that
- will be accessed and written to the data file.
-
- stmt. 2: gives 'recordnum' the value 27
-
- stmt. 3: reads the data file for record number 27
-
- stmt. 5: updates record 27, If successful, a NEW record
- will be written with the new value for 'phonenumber'.
-
- Note the record is read first to get the current values for
- the record. Updates are done by deleting the old record and
- writing the new changed record, using the current values of
- of the record layout string variables.
-
- You may at any time add additional fields to an existing record.
- Simply include the new fields in the record layout string and
- update the record. If you were going to add new fields to all
- records, then you would probably want to use two record layout
- strings. One string in the format as the record currently exists,
- and the second string in the format of the new layout. Then
- simply read the record with the current layout and update it with
- the new layout. (Dont forget to set the values of your new fields)
-
- RexxRMF.Library
-
-
- UPDKEY_RMF_RECORD
-
- UPDKEY_RMF_RECORD is used to update a record by key.
- The primary key does not have to change, but if you will be
- changing the primary key then you MUST use UPDKEY_RMF_RECORD
- else the indices will get screwed up.
-
- x = UPDKEY_RMF_RECORD(ix,record,okey,occr,nkey,[{ixnum1,altkey1}...])
-
- UPDKEY_RMF_RECORD accepts 15 arguments, 5 required, 10 optional.
-
- Inputs:
-
- 1). ix - global data pointer (from OPEN_RMF())
-
- 2). record - is a string which contains the variable names
- (record layout string)
-
- 3). okey - the current value of the primary key
- (ie. index 0)
-
- 4). occr - numeric, which occurence of the oldkey
- defaults to 1
-
- 5). nkey - the new value for the primary key (index 0)
- if not changing the key, then oldkey and
- newkey should be the same.
-
- 6-15). - alternate index key pairs
- these arguments must be specified in pairs
- they specify the alternate indexes and the
- key to be used with that index.
- If not specified the alternate index retains
- its current value when the record is updated.
-
- UPDKEY_RMF_RECORD returns 1 if the update succeeds, otherwise 0.
-
- eg.
-
- 1 old = 'kelly'
- 2 occur = 1
- 3 new = 'KELLY' (keys are case-sensitive)
- 4 x = UPDKEY_RMF_RECORD(ix,myrec,old,occur,new)
-
- Updates the primary index (0), replacing the first
- occurence of 'kelly' with 'KELLY'.
- or
- 4 x = UPDKEY_RMF_RECORD(ix,myrec,old,occur,old)
- old key value is retained
- or
- 4 x = UPDKEY_RMF_RECORD(ix,myrec,old,occur,new,1,area,4,zip)
-
- Updates the primary index, as well as index 1 & 4.
-
- If indices 2,3,5 are also being used, they will retain
- their current values, since the update did not specify
- new ones.
-
- RexxRMF.Library
-
-
-
- DELETE_RMF_RECORD
-
- DELETE_RMF_RECORD deletes records from the data file and index.
-
- x = DELETE_RMF_RECORD(ix,ixnum,record,key,{'K'|'R'|'L'},[occur])
-
- DELETE_RMF_RECORD accepts 6 arguments, 5 required, 1 optional.
-
- Inputs:
-
- 1). ix - global data pointer (from OPEN_RMF())
-
- 2). ixnum - integer specifies which index to use
- Note if deleting by an alternate index
- the primary node and all alternate nodes
- are deleted as well. This is a delete of
- the record and references to the record.
-
- 3). record - record layout string
- when a record is deleted the values from the
- deleted record are returned in the record
- layout string.
-
- 4). key - is an ARexx variable or string to be used as
- the key for the record.
-
- 5). 'K' or 'R' - parameter five must be either 'K','R', or 'L'.
- or 'L' same as READ_RMF_RECORD.
- DELETE_RMF_RECORD(...,1,'L') del last.
- DELETE_RMF_RECORD(...,2,'L') del next to last.
- 'P' and 'U' are not allowed..
-
- 6). occur - numeric, occurence of this key to delete
- meaningfull only if deleting by key ('K').
- (ie. their can only be one occurence of
- a particular record number, but
- multiple occurences of a key)
-
- DELETE_RMF_RECORD returns 1 if the delete succeeds, otherwise 0.
-
- eg.
-
- 1 myrecord = "deletedfname deletedlname deletedpnumber"
- 2 recordnum = 27
- 3 x = DELETE_RMF_RECORD(ix,0,myrecord,recordnum,'R')
-
- stmt. 1: defines the ARexx variable names that will receieve
- the values stored in the data record.
-
- stmt. 2: gives 'recordnum' the value 27
-
- stmt. 3: deletes record number 27, and updates the index.
-
- If successful, the ARexx variables specified in 'myrecord'
- will contain the values from the deleted record. Thus you
- know what the values were before the record was deleted and
- can write it back to the file if need be. Note these variables
- can be any variables you wish. (ie. you can use one record
- layout for reads/writes and another for deletes so as not to
- disturb the contents of your current read/write variables)
-
- RexxRMF.Library
-
-
-
-
-
-
- CLOSE_RMF
-
- This function releases the memory allocated to the tree,
- so it must be called when you are done processing the file.
-
- x = CLOSE_RMF(ix [,saveflag])
-
- CLOSE_RMF accepts two arguments.
-
- 1). ix - global data pointer (from OPEN_RMF())
-
- 2). saveflag - numeric, optional, use a value of 0 to specify
- that the index SHOULD BE SAVED.
-
- use a value of 1 to specify that the index is
- NOT TO BE SAVED.
-
- default is 0, save the index
-
-
- CLOSE_RMF returns 0 if the close succeeds, otherwise it returns a
- non-zero error code.
-
- RexxRMF.Library
-
-
-
- ANY_ERR
- ANY_ERROR
- ANY_ERRORS
-
- If any of the functions fail (return zero or NULL '0000 0000'x),
- this function can be used to interrogate the library for the error
- condition that caused the function to fail.
-
- x = ANY_ERR(ix)
-
- ANY_ERR accepts one argument.
-
- 1). ix - global data pointer (from OPEN_RMF())
-
- Values returned:
-
- RMF errors
-
- 4000 - RECORD_NOT_FOUND
- READ_RMF_RECORD failed (record does not exist)
-
- 4100 - NO_FILE_TO_SAVE_TO
- Attempt to save index file which was opened without a name.
-
- 4200 - RECORD_KEY_EXISTS
- Attempt to add key to index that did not allow duplicates.
-
- 4300 - NODE_ALLOCATION_FAILED
- Only occurs when memory allocation for node fails.
- (means you got less than 76 bytes of memory left !!)
-
- 4400 - MAX_KEYLEN_EXCEEDED
- Key length is greater than 512 bytes
-
- 4401 - ERROR_KEY_HAS_NO_LENGTH
- A zero length key was used.
-
- 4600 - MAXIMUM_INDICES_USED
- You should not get this error, you should get 4700 before this
- one will occur. If you do get this error it means you some
- how managed to get past the edit checks on index number and
- the AVL algorithm itself is complaining.
-
- 4700 - INVALID_INDEX_NUMBER
- Index number you specified was not valid.
- Means you used an index number < 0 or > 5.
-
- 4800 - INVALID_NODE_POINTER
- You should not get this error, but if you do it means a
- pointer to a tree node was used that had a NULL value.
-
- 4802 - INVALID_NODE_POINTER
- You should not get this error, but if you do it means a
- pointer to a tree node was used that had a NULL value.
-
- 4804 - INVALID_NODE_ODDPOINTER
- You should not get this error, but if you do it means a
- pointer to a tree node was used that had a illegal odd value.
-
- 4806 - CANNOT_LINK_PRIMENODES
- You tried to add_key() into index #0, and link it to another
- 'primenode' at the same time.
-
- 4900 - INVALID_RECORD_NUMBER
- You used a record number with value <= 0.
-
- 5000 - INVALID_DELETE_TYPE
- Record delete type was not 'K' or 'R'.
-
- RexxRMF.Library
-
-
-
- 5001 - INVALID_READ_TYPE
- Record read type was not 'K' or 'R' or 'P' or 'U'.
-
- 5100 - COULD_NOT_ADD_TO_DELETE_INDEX
- A record block was deleted that has no entry in the delete
- index. Simply means your file will have a delete block that
- RexxRMF will know nothing about. (similar to 4300)
-
- 5200 - TREE_NODE_DELETION_FAILURE
- If this occurs, call me, means the AVL algorithm aint working.
-
- 5300 - TREE_NODE_INSERTION_FAILURE
- If this occurs, call me, means the AVL algorithm aint working.
-
- 5600 - FILE_READ_ERROR
- An I/O error occured while reading the data file
-
- 5602 - FILE_READ_EOF
- Read past end of data file
-
- 5700 - FILE_WRITE_ERROR
- An I/O error occured while writing the data file
-
- 5800 - ERROR_READ_INDEX_IOERROR
- An I/O error occured while reading the index file
-
- 5801 - ERROR_READ_INDEX_ZEROKEY_LEN
- While loading index file encountered key with zero length.
- (ie. the record had no keys, neither primary nor alterate)
- Loading of the index is immediately terminated, you
- probably do not want to save the index if this occurs.
-
- 5802 - ERROR_READ_INDEX_MAXKEY_LEN
- While loading index encountered key which exceeded MAXKEYLEN.
-
- 5900 - ERROR_WRITE_INDEX_IOERROR
- An I/O error occured while writing the index file
-
- Dos errors
-
- If the error number is something less than the errors above
- then it indicates a DOS error (from IoErr())
-
- 103 - ERROR_NO_FREE_STORE
-
- 221 - ERROR_DISK_FULL
-
- 222 - ERROR_DELETE_PROTECTED
-
- 223 - ERROR_WRITE_PROTECTED
-
- 224 - ERROR_READ_PROTECTED
-
- (and any others that may occur, see AmigaDos manual)
-
- RexxRMF.Library
-
-
-
- Special Symbol Variables
-
- As mentioned above special variables can be used in the record layout
- string to return information about the record just read or written.
-
- The functions recognize nine special symbols, which must immediately
- precede a variable name within the record layout string.
-
- The special symbols are '@', '#', '&', '=', '<', '>', '-', '%' and '*'.
-
- '@' - returns the record address of the record just
- read/written. This is the relative byte location
- of were the record begins in the data file.
-
- '#n' - returns the occurence number of the record,
- 'n' is the index number.
-
- '&n' - returns the key of the record, useful if reading by
- position, 'n' is the index number.
- eg. If you read record number 32, this causes the
- key for record number 32 to be returned as well.
-
- '=n' - returns the record position within the index used to
- read/write the record, 'n' is the index number.
- This is the position of record key in sorted order.
-
- '<' - read only field, the fieldname following the '<' will NOT
- be written to the datafile during writes/updates, but will
- be loaded with data during reads.
-
- '>' - write only field, the fieldname following the '>' will NOT
- be loaded with data during reads, but will be written to the
- datafile during writes/updates.
-
- The intent of '<' and '>' was to allow a single layout string
- to be used for both reading and writing.
-
- '-' - suppresses the reading/writing of the data.
- useful when you want to skip over fields in a data
- record (or not change their current value).
- Be particularly watchful of this when doing writes,
- since the data will NOT be written to the file.
- When doing a read the variable is NOT loaded with
- data from the file. A field name need not follow
- the '-' when reading a record.
- eg. reclayout = "first last - - - address"
- will cause the three fields following 'last' in the data
- record to be skipped.
-
- '%' - returns the number of fields in the data record.
- For reads this is the total number of fields in the record,
- NOT the number of fields which were loaded with data.
- For writes this *IS* the number of fields that were actually
- written, NOT the number of fields in the record layout string.
- Note for reads/writes this count includes the primary key.
-
-
- '*n' - returns the actual memory address of the tree node for this
- record. 'n' is the index number. The value is returned as
- an ARexx hex-string. This value can then be used with the
- 'low' level functions described below.
-
- eg.
-
- @anyname the '@' does not take an index number
- stores the record address in the ARexx variable
- 'anyname'
-
- #3anyname stores the occurence of the record key within
- index 3 in the ARexx variable 'anyname'
-
- &1anyname stores the record key from index 1 in the
- ARexx variable 'anyname'
-
- =2anyname stores the position of the record within index 2
- in the ARexx variable 'anyname'
-
- -anyname the '-' does not take an index number
- skips the reading/writing of next field
- (remember record layout is positional)
-
- #anyname is the same as #0anyname, index 0 is the primary index
- =anyname is the same as =0anyname, etc.
-
- These special variables can be placed any where in the record
- layout string.
-
- eg. myrecord = " @rba firstname lastname =x0 =3x3 phonenumber"
-
- In the above record layout string three record values and
- three special variables will be returned. The special
- variables are rba, x0, and x3.
-
- success = READ_RMF_RECORD(ix,3,myrecord,phone,'K')
-
- This READ_RMF_RECORD call uses index 3 to read for a data record.
-
- The above READ_RMF_RECORD will return the following values:
-
- firstname, lastname, phonenumber will be 'stuffed' with data
- from the file.
-
- In the 'myrecord' layout string @rba, =x0, =3x3 are specified
-
- rba = physical location in the file from which the record was read
-
- x0 = relative position of the record in the primary index
- (ie. says this is the first, second, third, etc. record
- in the primary index.)
-
- x3 = relative position of the record in alternate index 3
-
- eg. if the file contained the following three records
-
- by primary, index 0 by index 3
- rec (indexing on lastname) (indexing on phone)
- location
- 1. 220 John Appleton 555-1232 | 555-1230 Mike Wilson
- 2. 908 Ron Kelly 555-1231 | 555-1231 Ron Kelly
- 3. 1705 Mike Wilson 555-1230 | 555-1232 John Appleton
-
-
- if the read returned the record for Mike Wilson
-
- then
- rba = 1705
-
- x0 = 3, ie. Mike Wilson is the third record
- when reading by the primary index
-
- x3 = 1, ie. Mike Wilson is the first record
- when reading by index 3.
-
-
- The same would be true for a WRITE_RMF_RECORD call, with the exception
- that data record values are not returned. Presumably they have the same
- values that were just written to the file.
-
- eg. myrecord = " @rba firstname lastname =x0 =3x3 phonenumber"
-
- success = WRITE_RMF_RECORD(ix,3,myrecord,phone,'K')
-
-
- The values from firstname, lastname, phonenumber would be left
- as they are. However, WRITE_RMF_RECORD would return to your ARexx
- program the variables:
-
- rba = location in the file where the record was written
-
- x0 = relative position of the record in the primary index
-
- x3 = relative position of the record in alternate index 3
-
- RexxRMF.Library
-
-
-
- Low Level Function Descriptions
-
-
- The record management functions are built on functions which directly
- manipulate the nodes of the tree. These 'low' level functions can be
- used by your ARexx program as well. These functions are particularly
- useful if you are simply searching for the existence of a key or record.
-
- Some of the functions return or accept pointers to the actual node
- in the tree, so be careful of when and where you use them.
-
- Do not intermix the 'low' level ADD/UPDATE/DELETE functions with
- the ...RMF_RECORD functions above. The index and data file will more
- than likely get screwed up if you start adding/deleting keys behind the
- back of the ...RMF_RECORD functions. The ADD/UPDATE/DELETE functions
- should only be used when you are managing the reading/writing of the
- data file yourself.
-
- The 'low' level functions do NOT perform any I/O to the data file,
- only the in memory tree structure is accessed. Thus when record
- content is not important, and only the existence or non-existence
- of a key value needs to be determined, it would be better to use
- these functions.
-
-
-
- 'low' level function descriptions:
-
-
- --------------------------------------------------------------------------
-
- ADD_KEY
-
- add_key(ix,ixnum,keydata,rba,[primenode])
-
- Add a node into the tree with the specified key.
-
- ix - pointer to global data
- (returned by open_rmf)
-
- ixnum - numeric, which index to use
- 0 = primary index
- 1 - 5 = alternate index
- Note if 'primenode' is specified, then 'ixnum'
- must be 1-5. ie. you cannot link a primenode to
- another primenode.
-
- keydata - string, key value to be inserted in tree
-
- rba - numeric, this is the relative block address
- of the record data for this key.
- eg. WRITE_RMF_RECORD() calls this function passing
- it the rba of where the record will be written.
-
- primenode - pointer, optional, a primary node pointer
- (ie. a node in index #0)
- If specified 'primenode' must be a node in index #0,
- and 'ixnum' must be > 0. (see 'ixnum' above)
- The newly added key will be 'linked' to this primenode.
- Thus creating alternate key paths to the same record.
-
- eg.1
- Lets say you do the following:
-
- primenode -------> node0 = ADD_KEY(ix,0,Lastname,rba0)
- its in index #0 node1 = ADD_KEY(ix,1,ZipCode,rba1)
- node2 = ADD_KEY(ix,2,State,rba2)
- node3 = ADD_KEY(ix,3,Employer,rba3)
- node4 = ADD_KEY(ix,4,DeptNo,rba4)
- node5 = ADD_KEY(ix,5,SocNum,rba5)
-
- This results in 6 nodes being added.
- Since RexxRMF keeps each index as a separate
- tree, the nodes are not 'related'. What you
- have is six INDEPENDENT indices on a file.
- (Which is ok, if thats what you want)
-
- If 'SocNum' is to be an alternate key for
- 'Lastname' the above won't do it unless
- 'rba5' = 'rba0'
-
- However if you do the following
-
- eg.2
- primenode -------> node0 = ADD_KEY(ix,0,Lastname,rba0)
- its in index #0 node1 = ADD_KEY(ix,1,ZipCode,rba1,node0)
- node2 = ADD_KEY(ix,2,State,rba2,node0)
- node3 = ADD_KEY(ix,3,Employer,rba3,node0)
- node4 = ADD_KEY(ix,4,DeptNo,rba4,node0)
- node5 = ADD_KEY(ix,5,SocNum,rba5,node0)
-
- Six nodes are still added, however the
- nodes 1-5 will be linked to node0. The
- 'rba' values used for nodes 1-5 five will
- be ignored and the 'rba' will be taken
- from node0. Thus all keys are pointing to
- the same record, and are alternates for node0.
-
- Note that in the first example above, if all the 'rba'
- values are the same you accomplish building alternate
- keys to the same record. The BIG difference is what
- happens whens deletions are made.
- In eg.1 deleting a key from index #5 simply deletes
- that key from that index (tree).
- In eg.2 deleting a key from index #5, will delete all
- key references (links) to the same record. Thus, the
- primenode as well as the other alternates are deleted.
-
-
- Returns - pointer (ARexx hex-string) to the tree node
- if successfully added, else NULL ('0000 0000'x)
-
-
-
- --------------------------------------------------------------------------
-
- DELETE_KEY
-
- delete_key(ix,ixnum,keydata,occur)
-
- Delete a tree node by key.
-
- If the deleted key occurs multiple times than all remaining keys will
- have their 'occurence' number adjusted to reflect the correct number
- of occurences.
-
- ix - pointer to global data
- (returned by open_rmf)
-
- ixnum - numeric, which index to use
-
- keydata - string, key to delete
-
- occur - which occurence to delete
-
- Returns - 1 if successful, else returns zero.
-
-
- --------------------------------------------------------------------------
-
- DELETE_POS
-
- delete_pos(ix,ixnum,pos)
-
- Delete a tree node by relative position.
-
- ie. If you build a tree with ten names,delete_pos(ix,0,6) will delete
- the sixth name (in sorted order) from the primary index.
-
- If the key deleted in position 'pos' occurs multiple times than all
- remaining keys will have their 'occurence' number adjusted to reflect
- the correct number of occurences.
-
- ix - pointer to a IndexFile struct.
- (returned by open_rmf)
-
- ixnum - numeric, which index to use
-
- pos - relative position of tree node to be deleted
-
-
- Returns - 1 if successful, else returns zero.
-
-
- --------------------------------------------------------------------------
-
- FIND_KEY
-
- find_key(ix,ixnum,keydata,occur)
-
- Search tree for specified key.
-
- Unlike LOCATE_KEY this function uses the entire key and the
- occurence number must match. READ_RMF_RECORD uses this function
- when you specify 'K'.
-
- ix - pointer to global data
- (returned by open_rmf)
-
- ixnum - numeric, which index to use
-
- keydata - pointer to keyvalue
-
- occur - numeric, which occurence to find
-
-
- Returns - pointer (ARexx hex-string) to the tree node
- if successful, else returns NULL ('0000 0000'x)
-
-
- --------------------------------------------------------------------------
-
- FIND_NEXT
-
- find_next(ix,ixnum )
-
- Find the next occurence of a key. This function should be called
- after FIND_KEY to sequentially find all occurences.
-
- Similar to locate_next() but does not allow partial key searches.
-
- ix - pointer to global data
- (returned by open_rmf)
-
- ixnum - numeric, which index to use
-
- Returns - pointer (ARexx hex-string) to the tree node
- if successful, else returns NULL ('0000 0000'x)
-
-
-
- --------------------------------------------------------------------------
-
-
- FIND_POS
-
- find_pos(ix,ixnum,pos)
-
- Search for tree node by relative position. This function allows
- searches to be done by the relative positions of the nodes, ie. in
- sorted order, thus random/sequential searches can be made.
- READ_RMF_RECORD uses this function when you specify 'R'.
-
- ix - pointer to global data
- (returned by open_rmf)
-
- ixnum - numeric, which index to use
-
- pos - numeric, relative position of node
- (ie. sorted order)
- If pos is negative the last node in the tree
- is returned. (any negative value will do)
- eg.
- treenode = find_pos(ix,0,-1)
- would return the last node in the primary index
-
- treenode = find_pos(ix,3,-1)
- would return the last node in index #3
-
- Returns - pointer (ARexx hex-string) to the tree node
- if successful, else returns NULL ('0000 0000'x)
-
-
-
-
- --------------------------------------------------------------------------
-
-
- LOCATE_KEY
-
- locate_key(ix,ixnum,keydata,occur)
-
- Search for the specified key. This function differs from
- FIND_KEY in that this function allows partial key searches.
- Use this function to initially set up for calls to LOCATE_NEXT().
- READ_RMF_RECORD uses this function when you specify 'P'.
-
- ix - pointer to global data
- (returned by open_rmf)
-
- ixnum - numeric, which index to use
-
- keydata - string, key to search for
-
- occur - occurence number to start with
-
- Returns - pointer (ARexx hex-string) to the tree node
- if successful, else returns NULL ('0000 0000'x)
-
-
-
- --------------------------------------------------------------------------
-
- LOCATE_NEXT
-
- locate_next(ix,ixnum )
-
- Find the next sequential key in the tree. This function should
- be called after LOCATE_KEY to find the next occurence of the key.
-
- This functions differs from FIND_NEXT in that this function
- allows partial keys to be searched.
-
-
- ix - pointer to global data
- (returned by open_rmf)
-
- ixnum - numeric, which index to use
-
- Returns - pointer (ARexx hex-string) to the tree node
- if successful, else returns NULL ('0000 0000'x)
-
- eg.
- if the tree contains the keys
-
- Johnson occurence 1
- Lewis occurence 1
- Thomas occurence 1
- Thomas occurence 2
- Thomas occurence 3
- Thomphson occurence 1
- Wilson occurence 1
-
- p = locate_key(ix,0,"Thom",1);
- will find the first occurence of Thomas
-
- p = locate_next(ix,0);
- will find the second occurence of Thomas
-
- p = locate_next(ix,0);
- will find the third occurence of Thomas
-
- p = locate_next(ix,0);
- will find the first occurence of Thomphson
-
- p = locate_next(ix,0);
- will return NULL since their no more keys beginning with
- "Thom".
-
- If the value specified for the occurence were 2 in the locate_key()
- call then the first occurence of 'Thomas' would be skipped, but
- all others would be found, including 'Thomphson'.
-
-
- --------------------------------------------------------------------------
-
- KEY_VALUE
-
- key_value(treenode [,ixnum])
-
- Returns the value of the key for the treenode, or the value of a
- key from an alternate of the treenode.
-
-
- treenode - pointer to a tree node, the functions
- ADD_KEY(), FIND_KEY(), FIND_NEXT(), FIND_POS(),
- LOCATE_KEY(), and LOCATE_NEXT() return pointers
- to tree nodes.
-
- ixnum - index number, 0-5, this parm is optional.
- If not specified the value of key for the
- treenode is returned.
- If an index number is specified, 0-5, then the
- value of the key for the specified alternate index
- node is returned.
-
- eg.
- lets say primary index (0) indexes on lastname
- and alternate index 2 indexes on zip code.
-
- treenode = find_key(ix,2,"60649",1)
-
- The above looks in alternate index 2 for the
- first occurence of zip code 60649, a pointer
- to the tree node is returned.
-
- Given the treenode returned from alternate
- index 2, we can get the value of the key in
- the primary index (0) with the statement:
-
- lname = key_value(treenode,0)
-
- This returns the value of 'lastname' associated
- with the treenode from alternate index 2.
-
-
- Similarly the values of the other alternate
- keys associated with 60649, can be obtained
- with
-
- alt1key = key_value(treenode,1)
- alt3key = key_value(treenode,3)
- alt4key = key_value(treenode,4)
- alt5key = key_value(treenode,5)
-
- Thus given a treenode the value of any of its
- keys primary or alternate can be obtained.
-
-
- The value of the zipcode is simply the value
- of the key for the treenode.
-
- zip = key_value(treenode) = 60649
- or
- zip = key_value(treenode,2) = 60649
- since index 2 indexes on zipcode
-
-
-
- Returns - string, the key for the node
-
-
- --------------------------------------------------------------------------
-
-
- KEY_COUNT
-
- key_count(ix,ixnum,key,{ 'K' | 'P' })
-
- Returns a count of the number treenodes with the value 'key'.
-
- ix - pointer to global data
- (returned by open_rmf)
-
- ixnum - index number, 0-5, (0=primary)
-
- key - string, value of key to be counted
-
- type - string, 'K' specifies that the entire key must
- match. 'P' specifies that partial matches of key
- be counted as well.
-
- eg. count = key_count(ix,3,"708",'K')
- counts the number of keys in alternate index 3
- with the value of "708".
-
- Returns - numeric, number of occurences of the key
-
-
- --------------------------------------------------------------------------
-
-
- KEY_OCCUR
-
- key_occur(treenode [,ixnum])
-
- Returns the occurence number of a tree node, or the occurence number
- of an alternate.
-
-
- treenode - pointer to a tree node, the functions
- ADD_KEY(), FIND_KEY(), FIND_NEXT(), FIND_POS(),
- LOCATE_KEY(), and LOCATE_NEXT() return pointers
- to tree nodes.
-
- ixnum - index number, 0-5, this parm is optional.
- If not specified the occurence number for the
- treenode is returned.
-
- If an index number is specified, 0-5, then the
- occurence number for the specified alternate index
- node is returned. This similar to KEY_VALUE, given
- a treenode the occurence number of any of its
- alternates can be obtained.
-
-
- Returns - numeric, the occurence number of the node
-
-
- --------------------------------------------------------------------------
-
- KEY_RBA
-
- key_rba(treenode)
-
- Returns the relative block address assigned to a tree node.
-
- treenode - pointer to a tree node, the functions
- ADD_KEY(), FIND_KEY(), FIND_NEXT(), FIND_POS(),
- LOCATE_KEY(), and LOCATE_NEXT() return pointers
- to tree nodes.
-
- Returns - numeric, relative block address assigned to the node.
- This is the value that was stored with the ADD_KEY()
- function.
-
- --------------------------------------------------------------------------
-
- NEXT_UNIQUE
-
- next_unique(ix,ixnum)
-
- Find the next unique occurence of a key. This function should be
- called after FIND_KEY to sequentially find all unique occurences.
- READ_RMF_RECORD uses this function when you specify 'U'.
-
-
- ix - pointer to global data
- (returned by open_rmf)
-
- ixnum - numeric, which index to use
-
- Returns - pointer (ARexx hex-string) to the tree node
- if successful, else returns NULL ('0000 0000'x)
-
-
-
- --------------------------------------------------------------------------
-
- NODE_POS
-
- node_pos(treenode [,ixnum])
-
- Returns the relative position (sorted order) of a node in the tree.
-
- treenode - pointer to a tree node, the functions
- ADD_KEY(), FIND_KEY(), FIND_NEXT(), FIND_POS(),
- LOCATE_KEY(), and LOCATE_NEXT() return pointers
- to tree nodes.
-
- ixnum - index number, 0-5, this parm is optional.
- If not specified the position (in sorted order) of
- the treenode is returned.
-
- If an index number is specified, 0-5, then the
- position of the key for the alternate index node
- is returned. This is similar to KEY_VALUE,
- given a treenode the relative sorted order of
- any of its alternate keys can be obtained.
-
-
- Returns - numeric, relative position of the node in the tree.
- (ie. sorted order)
-
- eg.
- if the tree contains the keys
-
- Johnson occurence 1
- Lewis occurence 1
- Thomas occurence 1
- Thomas occurence 2
- p --> Thomas occurence 3
- Thomphson occurence 1
- Wilson occurence 1
-
- and p points to the treenode containing the key 'Thomas occurence 3'
-
- then
-
- x = node_pos(p);
-
- will return 5 for the value of x, ie. Thomas occurence 3
- is the 5th node (sorted, relative to all other keys) in
- the tree.
-
-
- --------------------------------------------------------------------------
-
- SET_DATA
-
- set_data(treenode,n,string)
-
- Set data string stored with this tree node. This function allows
- you to store one or two data strings with the tree node. These
- strings can contain any information you wish to be associated with
- the tree node. This data does not get saved in the index file.
-
- treenode - pointer to a tree node, the functions
- ADD_KEY(), FIND_KEY(), FIND_NEXT(), FIND_POS(),
- LOCATE_KEY(), and LOCATE_NEXT() return pointers
- to tree nodes.
-
- n - numeric,
- use 0 to specify data string 1
- use 1 to specify data string 2
-
- string - string, text to be attached to the node
-
- Returns - always returns 1
-
- eg.
- x = set_data(treenode,1,"this is a test")
-
- after the above is executed, the treenode will have the
- text "this is a test" attached as data string 2. You
- can use the GET_DATA() function to later retrieve the
- data string attached to the node.
-
-
- --------------------------------------------------------------------------
-
- GET_DATA
-
- get_data(treenode ,n)
-
- Get data string stored with this tree node
-
- treenode - pointer to a tree node, the functions
- ADD_KEY(), FIND_KEY(), FIND_NEXT(), FIND_POS(),
- LOCATE_KEY(), and LOCATE_NEXT() return pointers
- to tree nodes.
-
- n - numeric, use 0 to specify data string 1
- use 1 to specify data string 2
-
- Returns - string, the stored string data
-
-
- --------------------------------------------------------------------------
-
- RexxRMF.Library
-
-
- RexxRMF Functions Summary
-
- number = ANY_ERR(ix) or ANY_ERROR(ix) or ANY_ERRORS(ix)
-
- ix = OPEN_RMF([filename] [,dup0] [,nodata])
-
- true/false = WRITE_RMF_RECORD(ix,record,key,[{ixnum1,altkey1}...5])
-
- true/false = READ_RMF_RECORD(ix,ixnum,record,key,{'K'|'R'|'P'|'U'},[occ])
-
- true/false = NEXT_RMF_RECORD(ix,ixnum,record)
-
- true/false = UPDATE_RMF_RECORD(ix,record,recnum,[{ixnum1,altkey1}...])
-
- true/false = UPDKEY_RMF_RECORD(ix,record,okey,occr,nkey,[ixnum1,altkey1])
-
- true/false = DELETE_RMF_RECORD(ix,ixnum,record,key,{'K'|'R'},[occ])
-
- number = CLOSE_RMF(ix,saveflag)
-
- treenode = ADD_KEY(ix,ixnum,keydata,rba)
-
- true/false = DELETE_KEY(ix,ixnum,keydata,occ)
-
- true/false = DELETE_POS(ix,ixnum,pos)
-
- treenode = FIND_KEY(ix,ixnum,keydata,occ)
-
- treenode = FIND_NEXT(ix,ixnum)
-
- treenode = FIND_POS(ix,ixnum,pos)
-
- string = GET_DATA(treenode,n)
-
- number = KEY_COUNT(ix,ixnum,key,{'K' | 'P'})
-
- number = KEY_OCCUR(treenode [,ixnum])
-
- number = KEY_RBA(treenode)
-
- string = KEY_VALUE(treenode [,ixnum])
-
- treenode = LOCATE_KEY(ix,ixnum,keydata,occ)
-
- treenode = LOCATE_NEXT(ix,ixnum)
-
- treenode = NEXT_UNIQUE(ix,ixnum)
-
- number = NODE_POS(treenode [,ixnum])
-
- true = SET_DATA(treenode,n,string)
-
- ----------------------------------
- true = 1, false = 0
- treenode = pointer (hex string)
-
- RexxRMF.Library
-
-
- File Maintenance:
-
-
- The RMF functions READ_RMF_RECORD/WRITE/UPDATE etc. perform all the
- the file I/O for the data file. When a data record is deleted its
- node entry in the tree is removed and the data block is marked as
- deleted by storing a zero in the record length field for the record.
- The RMF functions maintain a separate tree for deleted data records.
- The RMF functions attempt to re-use deleted data record blocks as
- much as possible.
-
-
- eg. lets say you have a single record in your data file
- with a total length of 500 bytes.
-
- you update the record so that the total length is reduced to 100
- bytes.
-
- this is whats gonna happen:
-
- 1. the recordlength of the data record is set to zero
- (you now have a file that has 500 bytes not used)
- (UPDATE_RMF_RECORD() will always do a delete of the record,
- then a write of the record)
-
- 2. an entry is made in the delete index identifing the
- location of where the deleted block occurs in the file.
- (this has to be at rba location zero, since their is only
- one record in the file)
-
- 3. the ARexx variables specified in the record string are
- accessed and the total length computed.
- (this is gonna be 100 bytes)
-
- 4. the delete index is searched for a block whose size is
- large enough to hold the 100 bytes. This results in location
- zero (it was just deleted) being chosen.
- (If no deleted block is large enough then the record will be
- written at the end of the file)
-
- 5. the block at location 0 is 500 bytes, we know this from the
- block length, we only need 100 bytes. The block at location
- zero gets split into two blocks.
-
- 6. the first block is used to hold the 100 bytes of data, a
- entry is made into the tree.
-
- 7. for the second block (balance of 400 bytes) starting at rba
- location 100, a record header is built and written to the data
- file. The record header will have a block length of 400, and
- a record length of zero. An entry will be made into the
- delete index that a delete block occurs at rba location 100.
-
- 8. you now have two records in the file, one of which is marked
- as deleted.
-
-
-
- 9. Now you start writing new records to the file, so go to step
- three above. Any new records written will attempt to re-use
- a deleted block first, splitting it as necessary.
-
- So whats the point, the point is eventually the deleted block
- will become too small to be reuseable. Imagine what happens
- when the delete index contains several (possibly hundreds)
- of delete blocks scattered throughout the file, things can
- get pretty fragmented. Included with the lib is a small
- utility program that will reload the data file and its index,
- eliminating the deleted blocks from both the data file and the
- index. You will want to do this (reload) since the delete
- index is loaded along with the primary and any alternates,
- if the deleted records are too small to be re-used then the
- memory used to hold the delete index is being wasted.
-
-
-
-
- Utility Programs
-
- rebuildrmfindex - rebuilds the index file from the data file.
- Only a index file is created, data file is left
- intact.
- If you crash anytime before saving the index,
- this program may be able to rebuild the index
- file.
-
- reloadrmfdata - removes deleted blocks from the data and index
- files. A new data file and new index file are
- created. For when your datafile gets really
- fragmented. This program is similar to the
- rebuildrmfindex program. However reloadrmfdata
- will cause the locations of all the data records
- to change, specifically the data records will be
- written to the new data file in key sorted order.
-
- dumprmfdata - Formatted dump of active data records.
-
- checkrmf - display some not-so interesting statistics
- about your index file.
-
- Source 'C' code is included for all the above utility programs.
- RexxRMF.Library
-
-
- Implementation Internals
-
- For those who wish to access the data file directly, since it is your
- data, the record format is given below.
-
- Data File Format:
-
- Each record in the data file has the following format
-
- record header + keydata + record data + 4 byte trailer
-
- The header is
-
- block length = reclength + 4byte trailer
- (ie. keydata + record data + 4)
-
- record length = total length of all fields in
- the record (including keys).
- (ie. keydata + record data)
- (deleted records have reclen = 0)
-
- field count = number of fields in record
-
- keydata = null terminated key strings, alternate keys have
- a leading 'index' identifier byte (hex F1,F2...)
-
- record data = individual data field strings, NULL terminated,
- in the order specifed by the record layout string
- when the record was written with WRITE_RMF_RECORD.
-
- trailer = 4 NULL bytes are written at the end of each record
-
- (NOTE the block/record length includes the NULL terminators)
-
- eg.
-
- |header|K0,0xf1,K1,0xf2,K2,0xf3,K3,0xf4,K4,0xf5,K5|data|4nulls|
-
- K0 = primary key null terminated
-
- 0xf1 this byte says the following key is for index 1
- K1 = alternate index 1 key null terminated
-
- 0xf2 this byte says the following key is for index 2
- K2 = alternate index 2 key null terminated
-
- 0xf3 this byte says the following key is for index 3
- K3 = alternate index 3 key null terminated
-
- 0xf4 this byte says the following key is for index 4
- K4 = alternate index 4 key null terminated
-
- 0xf5 this byte says the following key is for index 5
- K5 = alternate index 5 key null terminated
-
- The 0xf1-5 bytes are only present if an alternate is used.
-
- It is these key values that are used by the utility programs
- to rebuild an index.
-
- eg. data file record
-
- |record header|record keys | record data fields |terminate|
- | 20 | 16 | 8 | Kelly,null | var1,null... var8,null | 4 nulls |
-
- block len = 20
-
- reclen = 16
-
- #fields = 8
-
- key = Kelly (null terminated primary key)
-
- var1 thru var8, each var null terminated
-
- trailer of 4 nulls
-
- The following record is marked as deleted, it has a record length
- of zero.
-
- 20 | 0 | 0 | Kelly,null | var1,null... var8,null | 4 nulls |
-
-
- RexxRMF.Library
-
-
- Index File Format:
-
-
- Index file consist of a fixed length Index Header block
- followed by a varing number of variable length blocks. These variable
- blocks are the keys for the data file. (see the avl.structs.h file)
-
-
- fixeddata + [prime key,alt. keys] ... [prime key,alt. keys]
-
-
- |fixed || fixed index data, followed by variable length keydata ||
- |header | recaddr1,blklen,type,status,keylength[0]-keylength[7],
- keydatakeydatakeydatakeydatakeydatakeydatakeydatakeydata||
-
-
- eg. sample index block
-
- ||header bytes|22,10,0,A,5,0,3,2,0,0kelly708IL||
-
- |<---- Repeats for each key in the primary index ---->|
- |<------------ Fixed Length DI_Info --------->| varying |
- ||fixed | rba|blklen|type|status|L0|L1|L2|L3|L4|L5|L6|L7| keydata ||
- ||header | 22 | 10 | 0 | A |5 |0 |3 |2 |0 |0 |0 |0 |kelly708IL||
-
-
- L0 is length of key for index 0 (the primary index)
- L1 is length of key for alternate index 1
- L2 is length of key for alternate index 2, etc.
-
- A length of zero means the index not used for this record.
-
- keydata is scanned for the length specified in L0-L7
- this keydata is NOT null-terminated, so
-
- 'kelly' = key for index 0 (L0 = 5) this is the primary key
- '708' = key for index 2 (L2 = 3)
- 'IL' = key for index 3 (L3 = 2)
-
- index 1,4,5 are not used for this record since L1,L4,L5=0
-
- L6 - is not used.
-
- L7 - is used for delete index.
- if a non-zero value is in position L7 then record block is a
- deleted block.
- RexxRMF.Library
-
-
- Limitations:
-
- Key length - limited to 512 bytes max
-
- Record length - limited to 65K
-
- Alternate keys - limited to 5
-
- File size - none, other than those imposed by the system
-
- Memory - yes
-
- Tree size - limited by memory
- Entire tree is loaded into memory (sorry 'bout that).
- Each tree node consumes approx. 76bytes + length of key.
- Each alternate key is maintained as a separate tree.
- You can approximate amount of memory needed:
- if #recs in file = 500
- average keylen = 10 bytes
- mem = 500 x (76 + 10) = 43000
- if alternate keys are used then
- mem = mem x (number of indices)
-
- Stack Size - possibly
- Depends how big the tree gets. I suspect you will run
- out of memory before this becomes a problem. Insertions
- and deletions are NOT done recursively. The freeing
- of tree node memory is recursive.
-
- Tree Maint. - I made the assumption that primary use would be in
- searching and retrieving, and that few deletions
- would occur during processing of a file. Thus it
- is possible that the tree could become unbalanced
- when deleting records (or nodes).
- This is not a problem, its just that the tree does
- not live up to its name (balanced binary tree) after
- several deletions. If you are concerned about the tree
- becoming de-generate then simply close the file and
- reopen it.
-
- Note re-balancing *IS* done for insertions into
- the tree.
-
- Future Directions:
- Probably none.
-